Raspberry Pi PicoのSPI通信の練習
ラズピコ + PlatformIO + Arduino Framework(earlephihower) でSPI通信を行う練習。
SPItoMyselfという自分で送ったSPI通信を自分で受け取るサンプルプログラムがあるので、それを使って「データの送受信」と「波形データの観測」を行なってみる。
SPI Master (Serial Peripheral Interface)
サンプルプログラム SPItoMyself
code:SPItoMyself.ino
// Shows how to use SPISlave on a single device.
// Core0 runs as an SPI master and initiates a transmission to the slave
// Core1 runs the SPI Slave mode and provides a unique reply to messages from the master
//
// Released to the public domain 2023 by Earle F. Philhower, III <earlephilhower@yahoo.com>
// Wiring:
// Master RX GP0 <-> GP11 Slave TX
// Master CS GP1 <-> GP9 Slave CS
// Master CK GP2 <-> GP10 Slave CK
// Master TX GP3 <-> GP8 Slave RX
SPISettings spisettings(1000000, MSBFIRST, SPI_MODE0);
// Core 0 will be SPI master
void setup() {
SPI.setRX(0);
SPI.setCS(1);
SPI.setSCK(2);
SPI.setTX(3);
SPI.begin(true);
delay(5000);
}
int transmits = 0;
void loop() {
memset(msg, 0, sizeof(msg));
sprintf(msg, "What's up? This is transmission %d", transmits);
Serial.printf("\n\nM-SEND: '%s'\n", msg);
SPI.beginTransaction(spisettings);
SPI.transfer(msg, sizeof(msg));
SPI.endTransaction();
Serial.printf("M-RECV: '%s'\n", msg);
transmits++;
delay(5000);
}
// Core 1 will be SPI slave
volatile bool recvBuffReady = false;
int recvIdx = 0;
void recvCallback(uint8_t *data, size_t len) {
memcpy(recvBuff + recvIdx, data, len);
recvIdx += len;
if (recvIdx == sizeof(recvBuff)) {
recvBuffReady = true;
recvIdx = 0;
}
}
int sendcbs = 0;
// Note that the buffer needs to be long lived, the SPISlave doesn't copy it. So no local stack variables, only globals or heap(malloc/new) allocations.
void sentCallback() {
memset(sendBuff, 0, sizeof(sendBuff));
sprintf(sendBuff, "Slave to Master Xmission %d", sendcbs++);
SPISlave1.setData((uint8_t*)sendBuff, sizeof(sendBuff));
}
// Note that we use SPISlave1 here **not** because we're running on
// Core 1, but because SPI0 is being used already. You can use
// SPISlave or SPISlave1 on any core.
void setup1() {
SPISlave1.setRX(8);
SPISlave1.setCS(9);
SPISlave1.setSCK(10);
SPISlave1.setTX(11);
// Ensure we start with something to send...
sentCallback();
// Hook our callbacks into the slave
SPISlave1.onDataRecv(recvCallback);
SPISlave1.onDataSent(sentCallback);
SPISlave1.begin(spisettings);
delay(3000);
Serial.println("S-INFO: SPISlave started");
}
void loop1() {
if (recvBuffReady) {
Serial.printf("S-RECV: '%s'\n", recvBuff);
recvBuffReady = false;
}
}
配線
code:txt
// Wiring:
// Master RX GP0 <-> GP11 Slave TX
// Master CS GP1 <-> GP9 Slave CS
// Master CK GP2 <-> GP10 Slave CK
// Master TX GP3 <-> GP8 Slave RX
https://gyazo.com/7b0f4f0611163f5975a885d4f99ad377
https://gyazo.com/09a8b02eb808ec8a3c6771734d5db8c8
実行してみる
配線後、プログラムをラズピコへアップロードするとSPI通信が開始される。
送受信したデータがUSBシリアルへ出力されるので、出力データを眺めてみる。
シリアルコンソールとして screen コマンドを利用、
code:sh
screen /dev/cu.usbmodem1101 115200
以下のように送受信データが表示される
https://gyazo.com/869b16cfe717d3a345fce9770163411c
PulseViewを使った波形の計測
ロジアナのD0〜D3をラズピコのGP0〜GP3へ接続し、波形を眺める。
https://gyazo.com/ff406b2d1f7cef66400fb29221625dfd
出力された波形はこんな感じ。
https://gyazo.com/406726c99c8dcff4b60c00c67c5e0867
SPIの設定
サンプリングレート: 2MHz
サンプル数: 20M Samples
SPIの設定
https://gyazo.com/fc3a9f2ce56fb2c830008efec5e86028
Binary Decoder Output Viewを使うと16進数をアスキーとしても表示できる。
https://gyazo.com/106a59b8ce46f5c7ea3a7fb235039715
SPIの動作モード
モード0
クロックは正極性(通信を行わないときはLに固定、通信時にHのパルスを生成)
クロックパルスの最初でサンプル(立ち上がりエッジでサンプリング)
モード1
クロックは正極性(通信を行わないときはLに固定、通信時にHのパルスを生成)
クロックパルスの最後でサンプル(立ち下がりエッジでサンプリング)
モード2
クロックは負極性(通信を行わないときはHに固定、通信時にLのパルスを生成)
クロックパルスの最初でサンプル(立ち下がりエッジでサンプリング)
モード3
クロックは負極性(通信を行わないときはHに固定、通信時にLのパルスを生成)
クロックパルスの最後でサンプル(立ち上がりエッジでサンプリング)